package com.pb.wkflow.core.service.impl;

import com.pb.wkflow.api.controller.response.TaskResponse;
import com.pb.wkflow.api.entity.ParticipantUserEntity;
import com.pb.wkflow.api.entity.TaskHandOverEntity;
import com.pb.wkflow.api.mapper.ParticipantMapper;
import com.pb.wkflow.api.mapper.TaskHandOverMapper;
import com.pb.wkflow.core.camunda.bpmn.instance.Participants;
import com.pb.wkflow.core.entity.ActRuIdentityLinkEntity;
import com.pb.wkflow.core.entity.PostInfo;
import com.pb.wkflow.core.mapper.ActIdentityLinkMapper;
import com.pb.wkflow.core.service.UserParticipantService;
import com.pb.wkflow.core.utils.DateUtils;
import com.pb.wkflow.core.utils.ExpressionUtil;
import com.pb.wkflow.core.utils.SnowFlakeUuidGenerator;
import org.camunda.bpm.engine.delegate.DelegateTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 参与者服务
 * @author 苗益辉
 * @date 2022/5/9 14:17
 */
@Service
public class UserParticipantServiceImpl implements UserParticipantService {

    @Autowired
    ActIdentityLinkMapper actIdentityLinkMapper;

    @Autowired
    SnowFlakeUuidGenerator snowFlakeUuidGenerator;

    @Autowired
    ParticipantMapper participantMapper;

    @Autowired
    TaskHandOverMapper taskHandOverMapper;

    @Override
    public void saveUserTaskAssignment(DelegateTask delegateTask, String... userId) {
        List<ActRuIdentityLinkEntity> linkEntities = new ArrayList<>();
        List<String> userIds = Arrays.asList(userId);
        this.getHandOverUsers(userIds);
        for(String id : userIds) {
            ActRuIdentityLinkEntity identityLinkEntity = new ActRuIdentityLinkEntity();
            identityLinkEntity.setId(snowFlakeUuidGenerator.getNextId());
            identityLinkEntity.setUserId(id);
            identityLinkEntity.setTenantId(delegateTask.getTenantId());
            identityLinkEntity.setTaskId(delegateTask.getId());
            identityLinkEntity.setTaskDefKey(delegateTask.getTaskDefinitionKey());
            identityLinkEntity.setProcDefId(delegateTask.getProcessDefinitionId());
            identityLinkEntity.setProcInsId(delegateTask.getProcessInstanceId());
            identityLinkEntity.setType(Participants.TYPE_USER);
            identityLinkEntity.setCreateDt(DateUtils.dateToStr(new Date()));
            linkEntities.add(identityLinkEntity);
        }
        if(userIds.size() == 1) {
            delegateTask.setAssignee(userIds.get(0));
        }
        actIdentityLinkMapper.insertBatch(linkEntities);
    }

    @Override
    public void saveUserTaskAssignment(DelegateTask delegateTask, PostInfo postInfo) {
        List<PostInfo> postInfos = new ArrayList<>();
        postInfos.add(postInfo);
        saveUserTaskAssignment(delegateTask,postInfos);
    }

    @Override
    public void saveUserTaskAssignment(TaskResponse response, List<PostInfo> postInfos) {
        List<ActRuIdentityLinkEntity> actRuIdentityLinkEntityList = new ArrayList<>();
        this.getHandOverList(postInfos);
        this.participantProperties(response, postInfos, actRuIdentityLinkEntityList);
        actIdentityLinkMapper.insertBatch(actRuIdentityLinkEntityList);
    }

    @Override
    public void saveUserTaskAssignment(DelegateTask delegateTask, List<PostInfo> postInfos) {
        List<ActRuIdentityLinkEntity> actRuIdentityLinkEntityList = new ArrayList<>();
        this.getHandOverList(postInfos);
        this.participantProperties(delegateTask, postInfos, actRuIdentityLinkEntityList);
        actIdentityLinkMapper.insertBatch(actRuIdentityLinkEntityList);
    }

    /**
     * 解析参与者
     * @param participants 参与者实体
     * @param postInfo postInfo
     * @param variables 流程变量
     */
    @Override
    public void getParticipants(Participants participants, PostInfo postInfo, Map<String, Object> variables) {
        postInfo.setType(participants.getType());
        switch(participants.getType()) {
            case Participants.TYPE_ORG:
                postInfo.setOrgCode(ExpressionUtil.getVariablesValue(variables, participants.getId()));
                break;
            case Participants.TYPE_POS:
                postInfo.setPosCode(ExpressionUtil.getVariablesValue(variables, participants.getId()));
                break;
            case Participants.TYPE_USER:
                postInfo.setUserId(ExpressionUtil.getVariablesValue(variables, participants.getId()));
                break;
            case Participants.TYPE_JOB:
                postInfo.setJobCode(ExpressionUtil.getVariablesValue(variables, participants.getId()));
                break;
            case Participants.TYPE_ROLE:
                postInfo.setRoleCode(ExpressionUtil.getVariablesValue(variables, participants.getId()));
                break;
            case Participants.TYPE_POST:
                String expression = participants.getId();
                String[] expressions = expression.split("}\\{");
                for (int i = 0; i < expressions.length; i++) {
                    String expr = expressions[i];
                    if (i == 0) {
                        expr = expr.substring(1);
                    } else if (i == expressions.length -1) {
                        expr = expr.substring(0, expr.length() - 1);
                    }
                    String[] val = expr.split(":");
                    switch (val[0].toLowerCase(Locale.ROOT)) {
                        case Participants.TYPE_ORG:
                            postInfo.setOrgCode(ExpressionUtil.getVariablesValue(variables, val[1]));
                            break;
                        case Participants.TYPE_POS:
                            postInfo.setPosCode(ExpressionUtil.getVariablesValue(variables, val[1]));
                            break;
                        case Participants.TYPE_ROLE:
                            postInfo.setRoleCode(ExpressionUtil.getVariablesValue(variables, val[1]));
                            break;
                        case Participants.TYPE_JOB:
                            postInfo.setJobCode(ExpressionUtil.getVariablesValue(variables, val[1]));
                            break;
                        default:
                            break;
                    }
                }
                break;
            default:
                break;
        }
    }

    /**
     * 根据任务id删除当前参与者
     * @param taskId 任务id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRuIdentityLink(String taskId) {
        actIdentityLinkMapper.deleteByTaskId(taskId);
    }

    @Override
    public List<ActRuIdentityLinkEntity> getAssignee(String taskId, String tenantId) {
        return actIdentityLinkMapper.findUserList(taskId,tenantId);
    }

    @Override
    public List<ParticipantUserEntity> findUserByParticipants(List<PostInfo> postInfos) {
        return participantMapper.findUserByParticipants(postInfos);
    }

    private void getHandOverUsers(List<String> userIds) {
        if (!userIds.isEmpty() && userIds.size() > 1) {
            //如果有多条，查询多条人
            List<TaskHandOverEntity> taskHandOverEntities = taskHandOverMapper.queryHandOverUserList(userIds);
            List<String> taskHandOverUsers = taskHandOverEntities.stream()
                    .map(TaskHandOverEntity::getHandOverUserId).collect(Collectors.toList());
            userIds.addAll(taskHandOverUsers);
        } else if (userIds.size() == 1) {
            // 如果待办只有一个人，为了查询效率，直接查对应用户
            TaskHandOverEntity entity = taskHandOverMapper.queryHandOverUser(userIds.get(0));
            if (entity != null) {
                userIds.add(entity.getHandOverUserId());
            }
        }
    }

    private void getHandOverList(List<PostInfo> postInfos) {
        List<ParticipantUserEntity> participantUserEntities = participantMapper.findUserByParticipants(postInfos);
        List<String> userIds = participantUserEntities.stream().map(ParticipantUserEntity::getUserId)
                .distinct().collect(Collectors.toList());
        if (!userIds.isEmpty() && userIds.size() > 1) {
            //如果有多条，查询多条人
            List<TaskHandOverEntity> taskHandOverEntities = taskHandOverMapper.queryHandOverUserList(userIds);
            List<PostInfo> taskHandOverPostInfos = taskHandOverEntities.stream().
                    map(UserParticipantServiceImpl::handOverToPostInfoProperties).collect(Collectors.toList());
            postInfos.addAll(taskHandOverPostInfos);
        } else if (userIds.size() == 1) {
            // 如果待办只有一个人，为了查询效率，直接查对应用户
            TaskHandOverEntity entity = taskHandOverMapper.queryHandOverUser(userIds.get(0));
            if (entity != null) {
                PostInfo taskHandOverPostInfo = handOverToPostInfoProperties(entity);
                postInfos.add(taskHandOverPostInfo);
            }
        }
    }

    private void participantProperties(TaskResponse response,
                                       List<PostInfo> postInfos,
                                       List<ActRuIdentityLinkEntity> actRuIdentityLinkEntityList) {
        for(PostInfo postInfo : postInfos) {
            ActRuIdentityLinkEntity identityLinkEntity = new ActRuIdentityLinkEntity();
            identityLinkEntity.setId(snowFlakeUuidGenerator.getNextId());
            identityLinkEntity.setUserId(postInfo.getUserId());
            identityLinkEntity.setPosCode(postInfo.getPosCode());
            identityLinkEntity.setOrgCode(postInfo.getOrgCode());
            identityLinkEntity.setJobCode(postInfo.getJobCode());
            identityLinkEntity.setRoleCode(postInfo.getRoleCode());
            identityLinkEntity.setTenantId(response.getTenantId());
            identityLinkEntity.setTaskId(response.getTaskId());
            identityLinkEntity.setTaskDefKey(response.getActivityId());
            identityLinkEntity.setProcDefId(response.getProcessDefineId());
            identityLinkEntity.setProcInsId(response.getProcessInstanceId());
            identityLinkEntity.setType(postInfo.getType());
            identityLinkEntity.setCreateDt(DateUtils.dateToStr(new Date()));
            actRuIdentityLinkEntityList.add(identityLinkEntity);
        }
    }

    private void participantProperties(DelegateTask delegateTask,
                                       List<PostInfo> postInfos,
                                       List<ActRuIdentityLinkEntity> actRuIdentityLinkEntityList) {
        for(PostInfo postInfo : postInfos) {
            ActRuIdentityLinkEntity identityLinkEntity = new ActRuIdentityLinkEntity();
            identityLinkEntity.setId(snowFlakeUuidGenerator.getNextId());
            identityLinkEntity.setUserId(postInfo.getUserId());
            identityLinkEntity.setPosCode(postInfo.getPosCode());
            identityLinkEntity.setOrgCode(postInfo.getOrgCode());
            identityLinkEntity.setJobCode(postInfo.getJobCode());
            identityLinkEntity.setRoleCode(postInfo.getRoleCode());
            identityLinkEntity.setTenantId(delegateTask.getTenantId());
            identityLinkEntity.setTaskId(delegateTask.getId());
            identityLinkEntity.setTaskDefKey(delegateTask.getTaskDefinitionKey());
            identityLinkEntity.setProcDefId(delegateTask.getProcessDefinitionId());
            identityLinkEntity.setProcInsId(delegateTask.getProcessInstanceId());
            identityLinkEntity.setType(postInfo.getType());
            identityLinkEntity.setCreateDt(DateUtils.dateToStr(new Date()));
            actRuIdentityLinkEntityList.add(identityLinkEntity);
        }
    }

    private static PostInfo handOverToPostInfoProperties(TaskHandOverEntity entity) {
        PostInfo postInfo = PostInfo.builder().build();
        postInfo.setUserId(entity.getHandOverUserId());
        postInfo.setType(Participants.TYPE_USER);
        return postInfo;
    }
}
